package cn.tsvtc.shop.service.impl;


import cn.hutool.core.util.IdUtil;
import cn.tsvtc.shop.constant.RedisConstant;
import cn.tsvtc.shop.entity.ResultMessage;
import cn.tsvtc.shop.mapper.UserMapper;
import cn.tsvtc.shop.pojo.RegisterEmailUser;
import cn.tsvtc.shop.pojo.RegisterPhoneUser;
import cn.tsvtc.shop.pojo.User;
import cn.tsvtc.shop.service.CodeService;
import cn.tsvtc.shop.service.UserService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.Cookie;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: Athena
 * @date: 2020/10/29 17:18
 * @description: 用户服务
 */
@Slf4j
@Service
@Transactional
public class UserServiceImpl implements UserService {

    private UserMapper userMapper;

    private RedisTemplate redisTemplate;

    private CodeService codeService;

    private StringRedisTemplate stringRedisTemplate;

    private BCryptPasswordEncoder bcryptPasswordEncoder;

    @Autowired
    public UserServiceImpl(UserMapper userMapper,CodeService codeService, RedisTemplate redisTemplate,StringRedisTemplate stringRedisTemplate,BCryptPasswordEncoder bcryptPasswordEncoder){
        this.userMapper=userMapper;
        this.redisTemplate=redisTemplate;
        this.codeService=codeService;
        this.stringRedisTemplate=stringRedisTemplate;
        this.bcryptPasswordEncoder=bcryptPasswordEncoder;
    }



    /**
     * 插入新用户
     *
     * @param user
     * @return
     */
    @Override
    public ResultMessage<String> insert(User user) {
        //待插入用户对象
        User userForInsert=null;
        //状态
        Integer status=0;
        if(user instanceof RegisterPhoneUser){
            //手机注册的，检查验证码,并激活置1
            RegisterPhoneUser phoneUser= (RegisterPhoneUser) user;
            //1.获取redis对应验证码
            Object value = redisTemplate.opsForValue().get(RedisConstant.SHOP_REGISTER + user.getPhone());
            //2.校验验证码
            if(value==null){
                //空即没有对应验证码，即没有还获取验证码，或者已经过期
                return new ResultMessage<String>(false,"failed","请获取验证码");
            }else{
                //非空即有验证码，进行校验
                if(phoneUser.getCode().equalsIgnoreCase(value.toString())){
                    //验证码正确
                    //存入数据库
                    userForInsert=new User();
                    //设置用户名随机
                    userForInsert.setUsername(IdUtil.simpleUUID().substring(0,9));
                    //设置电话以及密码
                    userForInsert.setPhone(phoneUser.getPhone());
                    userForInsert.setPassword(phoneUser.getPassword());
                    //使用验证码注册直接激活为1
                    userForInsert.setStatus(1);
                    //插入
                }else {
                    //验证码错误
                    return new ResultMessage<String>(false,"failed","验证码错误");
                }
            }
        }else if(user instanceof RegisterEmailUser){
            //邮箱注册的，自动未激活0并进行发送邮件
            RegisterEmailUser emailUser= (RegisterEmailUser) user;
            Boolean mailResult = codeService.sendEmailCode(emailUser);
            log.info("邮件发送结果===> { }"+mailResult);
            userForInsert=new User();
            //设置用户名随机
            userForInsert.setUsername(IdUtil.simpleUUID().substring(0,9));
            //设置邮箱以及密码
            userForInsert.setEmail(emailUser.getMail());
            userForInsert.setPassword(emailUser.getPassword());
            //使用邮箱注册默认不激活为0
            userForInsert.setStatus(0);
            //插入
        }else{
            //暂无直接注册方式，直接返回失败
            return new ResultMessage<String>(false,"failed","注册异常，请检查网络并重试");
        }

        //从redis读取user列表，检查是否重复，不重复则插入
        //List<User> usersFromRedis = redisTemplate.opsForList().range("t_user", 0, -1);

        Map<Long,User> map = redisTemplate.opsForHash().entries("t_user");

        Boolean duplicate = this.checkUserDuplicate(userForInsert);
        if (duplicate) {
            //重复
            return new ResultMessage<String>(false,"failed","您已经注册过了");
        }else {
            //不重复,处理数据
            //设置创建日期以及修改日期
            userForInsert.setCreateTime(new Date());
            userForInsert.setUpdateTime(new Date());
            //密码加密
            userForInsert.setPassword(bcryptPasswordEncoder.encode(user.getPassword()));
            //设置创建者和更新者为自己0
            userForInsert.setCreater(0);
            userForInsert.setUpdater(0);
            //设置权限为普通用户
            userForInsert.setFlag(1);
            //写入数据库
            int result = userMapper.insert(userForInsert);
            // 插入redis
            //redisTemplate.opsForList().leftPush("t_user",userForInsert );

            redisTemplate.opsForHash().put("t_user",userForInsert.getId(),userForInsert);

            ResultMessage<String> stringResultMessage = new ResultMessage<>();
            stringResultMessage.setData("注册成功");
            return stringResultMessage;
        }
    }

    /**
     * 获取所有用户
     *
     * @return
     */
    @Override
    public List<User> selectAll() {
        List<User> users = userMapper.selectAll();
        return users;
    }

    /**
     * 检测用户是否重复
     *
     * @param user
     * @return
     */
    @Override
    public Boolean checkUserDuplicate(User user) {
        //从redis读取user列表
        //List<User> usersFromRedis = redisTemplate.opsForList().range("t_user", 0, -1);
        //List<User> usersFromRedis=new ArrayList<>();
        Map<Long,User> map = redisTemplate.opsForHash().entries("t_user");



        //System.out.println("usersFromRedis====>"+usersFromRedis);
        //System.out.println("user====>"+user);
        if(map!=null&&map.size()>0){

            for(Map.Entry<Long,User> entry : map.entrySet()){
                Long mapKey = entry.getKey();
                User mapValue = entry.getValue();
                System.out.println(mapKey+":"+mapValue);
                if(user.getPhone()!=null&&mapValue.getPhone()!=null){
                    if (mapValue.getPhone().equals(user.getPhone())) {
                        //检查到重复用户
                        return true;
                    }
                }
                if(user.getUsername()!=null&&mapValue.getUsername()!=null){
                    if (mapValue.getUsername().equals(user.getUsername())) {
                        //检查到重复用户
                        return true;
                    }
                }
                if(user.getEmail()!=null&&mapValue.getEmail()!=null){
                    if (mapValue.getEmail().equals((user).getEmail())) {
                        //检查到重复用户
                        return true;
                    }
                }
            }


//            for (User fromRedi : usersFromRedis) {
//                if(user.getPhone()!=null&&fromRedi.getPhone()!=null){
//                    if (fromRedi.getPhone().equals(user.getPhone())) {
//                        //检查到重复用户
//                        return true;
//                    }
//                }
//                if(user.getUsername()!=null&&fromRedi.getUsername()!=null){
//                    if (fromRedi.getUsername().equals(user.getUsername())) {
//                        //检查到重复用户
//                        return true;
//                    }
//                }
//                if(user.getEmail()!=null&&fromRedi.getEmail()!=null){
//                    if (fromRedi.getEmail().equals((user).getEmail())) {
//                        //检查到重复用户
//                        return true;
//                    }
//                }
//
//            }
        }

        return false;
    }

    /**
     * 登录
     *
     * @param map
     * @return
     */
    @Override
    public ResultMessage<String> login(Map map) {
        //检查发送来的用户名密码，进行user对象查验
        String uname = (String) map.get("uname");
        String password = (String) map.get("password");
        ResultMessage<String> message=new ResultMessage<>(false,"failed","登录异常");
        User loginedUser=null;
        if(uname!=null&&password!=null) {
            Map<Long, User> userMapmap = redisTemplate.opsForHash().entries("t_user");

            if (userMapmap != null && userMapmap.size() > 0) {
                //从redis加载user表
                for (Map.Entry<Long, User> entry : userMapmap.entrySet()) {
                    Long mapKey = entry.getKey();
                    User mapValue = entry.getValue();
                    if (uname.contains("@")) {
                        //邮箱登录
                        if(mapValue.getEmail()!=null){
                            if(mapValue.getEmail().equals(uname)){
                                //邮箱相同
                                if (bcryptPasswordEncoder.matches(password,mapValue.getPassword())) {
                                    //用户名密码相符
                                    loginedUser=mapValue;
                                    //将登录成功的user数据返回
                                    message.setState(true);
                                    //存入message 时格式为login_token_   +  UUID
                                    String uuid=IdUtil.simpleUUID();
                                    message.setMessage(uuid);
                                    message.setData(JSON.toJSONString(mapValue));
                                    break;
                                }else {
                                    //用户名密码不相符
                                    message.setState(false);
                                    message.setMessage("failed");
                                    message.setData("用户名密码不相符");
                                }
                            }else {
                                //没有对应用户名
                                message.setState(false);
                                message.setMessage("failed");
                                message.setData("用户名密码不相符");
                            }
                        }

                    } else {
                        //电话号登录
                        if(mapValue.getPhone()!=null){
                            if(mapValue.getPhone().equals(uname)){
                                //电话号相同
                                if (bcryptPasswordEncoder.matches(password,mapValue.getPassword())) {
                                    //用户名密码相符
                                    loginedUser=mapValue;
                                    //将登录成功的user数据返回
                                    message.setState(true);
                                    //存入message 时格式为login_token_   +  UUID
                                    String uuid=IdUtil.simpleUUID();
                                    message.setMessage(uuid);
                                    message.setData(JSON.toJSONString(mapValue));
                                    break;
                                }else {
                                    //用户名密码不相符
                                    message.setState(false);
                                    message.setMessage("failed");
                                    message.setData("用户名密码不相符");
                                }
                            }else {
                                //没有对应用户名
                                message.setState(false);
                                message.setMessage("failed");
                                message.setData("用户名密码不相符");
                            }
                        }

                    }


                }
            }
            //redis中user表数据错误，需要从数据库查验
            if (uname.contains("@")) {
                //邮箱
                User byPhone = userMapper.findByPhone(uname);
                if(byPhone!=null){
                    if (bcryptPasswordEncoder.matches(password,byPhone.getPassword())) {
                        //用户名密码相符
                        loginedUser=byPhone;
                        //将登录成功的user数据返回
                        message.setState(true);
                        //存入message 时格式为login_token_   +  UUID
                        String uuid=IdUtil.simpleUUID();
                        message.setMessage(uuid);
                        message.setData(JSON.toJSONString(byPhone));
                    }else {
                        //用户名密码不相符
                        message.setState(false);
                        message.setMessage("failed");
                        message.setData("用户名密码不相符");
                    }
                }
            }else {
                //电话
                User byEmail = userMapper.findByEmail(uname);
                if(byEmail!=null){
                    if (bcryptPasswordEncoder.matches(password,byEmail.getPassword())) {
                        //用户名密码相符
                        loginedUser=byEmail;
                        //将登录成功的user数据返回
                        message.setState(true);
                        //存入message 时格式为login_token_   +  UUID
                        String uuid=IdUtil.simpleUUID();
                        message.setMessage(uuid);
                        message.setData(JSON.toJSONString(byEmail));
                    }else {
                        //用户名密码不相符
                        message.setState(false);
                        message.setMessage("failed");
                        message.setData("用户名密码不相符");
                    }
                }
            }
        }
        //查验通过后就存cookie并存入login_token到redis,2小时有效

        redisTemplate.opsForValue().set(RedisConstant.LOGIN_TOKEN +message.getMessage() ,loginedUser,2, TimeUnit.HOURS);
        //查验不通过就直接返回失败
        return message;
    }

    /**
     * 自动登录
     *
     * @param cookie
     * @return
     */
    @Override
    public ResultMessage<String> autoLogin(Cookie cookie) {
        return null;
    }

    /**
     * 获取已经登录用户
     *
     * @param uuid
     * @return
     */
    @Override
    public User getStateOfLoginedUser(String uuid) {
        //向redis查询对应token
        Object tokenUser = redisTemplate.opsForValue().get(RedisConstant.LOGIN_TOKEN + uuid);
        if (tokenUser != null) {
            //查找到则返回用户对象到控制器(已登录)
            User user= (User) tokenUser;
            return user;
        }else{
            //未找到则返回空和失败(未登录)
            return null;
        }
    }

    /**
     * 已经登录用户退出登录
     *
     * @param uuid
     * @return
     */
    @Override
    public Boolean logoutByLoginedUser(String uuid) {
        //从redis中移除信息
        Boolean delete = redisTemplate.delete(RedisConstant.LOGIN_TOKEN + uuid);
        log.error("从redis中删除登录===> "+RedisConstant.LOGIN_TOKEN + uuid);
        log.error("从redis中删除登录结果===>"+delete);
        return delete;
    }


}
